/**
 * 
 * 1. import myModule from '@/utils/myModule'; // 获得模块类
 * 2. var mpCanvas = myModule.get('mpCanvas); // 获得模块
 * 3. mpCanvas.render() // 获得模块的方法
 * 
 */

/*
 
  Module mechanism
  modules = {
    moduleA: {
      method1: function(){},
      method2: function(){},
      method3: function(){},
      method4: function(){}
    },

    moduleB: {
      method1: function(){},
      method2: function(){},
      method3: function(){},
      method4: function(){}
    }
  };



*/
import mpvue from "./mpvue";
"use strict";
var myModule = (function(){
  const modules = {};

  function define(name, depends, implement){
    modules[name] = implement.apply(null, mapDepends(depends));
  }

  function mapDepends (depends) { // input: ['moduleA', 'moduleB' ...] output: [{method1, method2}, {method1, method2} ...] tips: one to one
    var i;
    if(!depends || !depends.length) return [];
    i = depends.length;
    while (i--) {
      depends[i] = modules[depends[i]];
    }
    return depends;
  }

  function get(name){
    return modules[name];
  }

  return { define: define, get: get };
})();

myModule.define('types', [], function(){ // 类型判断
  function isFunction(obj){
    return Object.prototype.toString.call(obj) === "[object Function]";
  }
  function isNull(obj){
    return Object.prototype.toString.call(obj) === "[object Null]";
  }
  function isNumber(obj){
    return Object.prototype.toString.call(obj) === "[object Number]";
  }
  function isString(obj){
    return Object.prototype.toString.call(obj) === "[object String]";
  }
  function isArray(obj){
    return Object.prototype.toString.call(obj) === "[object Array]";
  }
  function isUndefined(obj){
    return Object.prototype.toString.call(obj) === "[object Undefined]";
  }
  function isObject(obj){
    return Object.prototype.toString.call(obj) === "[object Object]";
  }
  function isDate(obj){
    return Object.prototype.toString.call(obj) === "[object Date]";
  }
  function isRegExp(obj){
    return Object.prototype.toString.call(obj) === "[object RegExp]";
  }
  function isMath(obj){
    return Object.prototype.toString.call(obj) === "[object Math]";
  }

  function isPhone(str){
    var reg=/^[1][3,4,5,7,8,9][0-9]{9}$/;
    return reg.test(phone);
  }

  function isEmail(str){
    var reg = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
    return reg.test(str);
  }

  function isIdCard(str){
    var reg = /^\d{15}|\d{18}$/;
    return reg.test(str);
  }

  function isValid(str){
    var reg = /^[a-zA-Z][a-zA-Z0-9_]{4,15}$/;
    return reg.test(str);
  }

  function isCnChar(str){
    var reg = /[\u4e00-\u9fa5]/;
    return reg.test(str);
  }


  return {
    isFunction: isFunction,
    isNull:isNull,
    isNumber:isNumber,
    isString:isString,
    isArray:isArray,
    isUndefined:isUndefined,
    isObject:isObject,
    isDate:isDate,
    isRegExp:isRegExp,
    isMath:isMath,
    isEmail:isEmail,
    isIdCard:isIdCard,
    isCnChar:isCnChar,
    isValid:isValid,
    isPhone: isPhone
  };
});

myModule.define('delay', ["types"], function(types){  // 延迟做一些事

  function doThing (fn, wait, tipsInfo, arrOptions=[], self=null) {
    if(!types.isFunction(fn)) return console.error("请传入函数！");
    if(!types.isArray(arrOptions)) return console.error("参数必须为数组");

    wait = parseInt(wait);
    tipsInfo && mpvue.showToast({title: tipsInfo});
    var timer= setTimeout(function(){

      mpvue.hideToast();
      fn.apply(self, arrOptions);
    }, wait);
    
  }

  return {doThing, doThing};

});

myModule.define('requestKey', ["types"], function(types){  // http request : query key  add key http request completed: remove key

  // requestList: { key: true}
  var requestList = {} //api请求记录
  // 将当前请求的api记录起来

  function add (key) {

     requestList[key] = true
  
  }
  
   
  
  // 将请求完成的api从记录中移除
  
  function remove (key) {
  
     delete requestList[key]
  
  }
  
   
  
  //当前请求的api是否已有记录
  
  function has (key) {
  
     return requestList[key]
  
  }

  function get (data) {

   if (!types.isObject(data)) return data;

  var ajaxKey = JSON.stringify(data);

   return ajaxKey;

  }

  return {add: add, remove: remove, has: has, get: get};

});


myModule.define('myString', ['types'], function(types){  // 

  function preFixAny (str, size=2, char=0) {
    return (Array(+size).join(char) + str).slice(-size);
  }

  function joinQuery (url, queryObj){ //拼接url参数
    if(!types.isString(url) || !queryObj || !types.isObject(queryObj) || JSON.stringify(queryObj) === '{}') return url;
    
    var options = [];
    for (var i in queryObj) {
      var str = i + "=" + queryObj[i];
      options.push(str);
    }
    options = options.join("&");
    url = url + "?" + options;
    return url;
  }
  
  function parseQuery (url) { // 把url参数转换为对象
    if(!url || !types.isString(url) || !/\?/.test(url)) return url;

    var str = url.split('?')[1];
    var result = {};
    var temp = str.split('&');
    for(var i=0; i<temp.length; i++)
    {
      var temp2 = temp[i].split('=');
      result[temp2[0]] = temp2[1];
    }

    return result;
  }

  function checkBeforeLogin(username, password) {  //是否通过登录前的检查，通过返回true， 否则返回false
    var err;
    username = username.trim();
    password = password.trim();
    if (username && password && username.length >= 3 && password.length >= 3) return {isPass: true};
    if (!username) {
      err = '用户名不能为空!';
    } else if (!password) {
      err = '密码不能为空!';
    } else if (username.length < 3) {
      err = '用户名个数必须大于三个';
    } else if (password.length < 3) {
      err = '密码个数必须大于三个!';
    }
    return {isPass: false, err: err};
  }

  function formatTime (date) {
    const year = date.getFullYear()
    const month = date.getMonth() + 1
    const day = date.getDate()
  
    const hour = date.getHours()
    const minute = date.getMinutes()
    const second = date.getSeconds()
  
    const t1 = [year, month, day].map(preFixAny).join('/')
    const t2 = [hour, minute, second].map(preFixAny).join(':')
  
    return `${t1} ${t2}`
  }

  function getBytes (str) {
    let len = str.length, bytes = len, charCode = -1;
    for (let i = 0; i < len; i++) {
      charCode = str.charCodeAt(i);
      if (charCode > 255)
        bytes++
    }
    return bytes;
  }

  function splitByLen (str, length, separator) {
    var arr = null;
    if (getBytes(str) <= length && separator) {   //如果本身长度就不够，则返回本身的数组
      arr = str.split(separator);
      return arr;
    } else if (getBytes(str) <= length && !separator) {
      return [str];
    }
  
    // 以下都是字符的长度，大于指定的长度
  
    if (separator) {   //如果指定了分隔符
      arr = str.split(separator);
    } else { //没有指定，则把回车替换为空格
      str = str.replace(/\n/g, ' ');
      arr = [str];
    }
  
  
    let resArr = [];  // 结果分割数组
    arr.forEach((v, i) => {
      if (getBytes(str) <= length) {
        resArr.push(v);
      } else {
        let charCode = -1, value, curLen = 0, len = v.length, startIndex = 0;
        for (let i = 0; i < len; i++) {
          charCode = v.charCodeAt(i);
          if (charCode >= 0 && charCode <= 255)
            curLen++;
          else
            curLen += 2;
  
          if (curLen > length) {
            value = v.slice(startIndex, i);
            resArr.push(value);
            startIndex = i;
            charCode > 255 ? (curLen = 2) : (curLen = 1);
          }
  
          if (i == len - 1 && curLen <= length) {   //循环到最后一个了, 并且没有超过最大的长度时
            value = v.slice(startIndex, i + 1);
            resArr.push(value);
          }
        }
      }
    });
  
    return resArr;    
  }



  return {
    getBytes: getBytes,
    splitByLen: splitByLen,
    preFixAny: preFixAny,
    joinQuery: joinQuery,
    parseQuery: parseQuery,
    formatTime: formatTime,
    checkBeforeLogin: checkBeforeLogin
  }
});


myModule.define('mpCanvas', ['myString', 'types'], function(myString, types){
  // 功能： 1. 渲染canvas， draw（）。 2. 生成图片或base64
  var canvasWidth, canvasHeight;
  // Only entrance
  async function render (width, height, data, canvasId='canvas') {
    // console.log('render');
    // checkout
    if(!this) return console.error('invoking render without canvasContext');
    if(!data || !types.isArray(data)) return console.error('data muse have and data muse be Array type');
    canvasWidth = width; canvasHeight = height;
    // Start distributing
    data.forEach(dataItem => {
      
      switch (dataItem.type) {

        case 'image':
        // console.log('image');
        _renderImageByStyle.call(this, dataItem.props.src, dataItem.style);
          
        break;

        case 'text': 
        // console.log('text');  
        _renderTextByStyle.call(this, dataItem.text, dataItem.style);

        break;

        case 'rect': 
        // console.log('rect');  
        _renderRectByStyle.call(this, dataItem.style);

        break;

        case 'clearRect': 
        // console.log('clearRect');
        _clearRect.call(this, dataItem.style.left, dataItem.style.top, dataItem.style.width, dataItem.style.height);

        break;
      }

    });
  
    this.draw();  // Start drawing
    return await _getCanvasTempFilePath.call(this,canvasId);
  }

  // private method

  async function _renderImageByStyle (src, { width, height, left=0, top=0 }) { // 使用style画图片
    
    if(!src || !src.trim()) return;
    width === '100%' && (width = canvasWidth),  height === '100%' && (height = canvasHeight);
    _renderImage.call(this, src, left, top, width, height);
  }

  function _renderTextByStyle (text, {left, top, fontSize, color, width, rowSpacing}) { // 使用style画文字
    var len, rowText,arrText, rowTop = top;

    fontSize && (this.font = fontSize + 'px "microsoft yahei",Helvetica,Arial');
    color && (this.fillStyle= color);
    
    if (width) { // 对文字进行换行处理

      len = width/fontSize*2;
      arrText = myString.splitByLen(text, len);
      fontSize -= 4;
      while(arrText.length > 0){
        rowText = arrText.shift();
        rowTop = rowTop + (rowTop === top? fontSize : rowSpacing + fontSize);
        
        _renderText.call(this, rowText, left, rowTop);
      }

    }else{ // 单行处理
      fontSize -= 4;
      top = top + fontSize;
      _renderText.call(this, text, left, top);
    }

   
    
  }

  function _renderRectByStyle ({width, height, left, top, backgroundColor, borderRadius=0, borderWidth, borderColor}) { // 使用style画矩形，圆角矩形，圆
    width === '100%' && (width = canvasWidth),  height === '100%' && (height = canvasHeight);
    if(+width === 0 || +height === 0) return;
    if (borderRadius === '50%') { // 画圆
      if (backgroundColor) {
        
        _renderCircle.call(this, left + width/2, top + width/2, width/2, true, backgroundColor);
      }

      if (borderWidth) {
        _renderCircle.call(this, left + width/2, top + width/2, width/2, false, borderColor);
      }

    }else if (borderRadius) { // 画圆角矩形
      
      if (backgroundColor) {
        
        _renderRoundRect.call(this, left, top, width, height, borderRadius, true, backgroundColor);
      }

      if (borderWidth) { 
        _renderRoundRect.call(this, left, top, width, height, borderRadius, false, borderColor, borderWidth);
      }

    }else{ // 画直角矩形

      if (backgroundColor) {
        
        _renderRect.call(this, left, top, width, height, true, backgroundColor);
      }

      if (borderWidth) { 
        _renderRect.call(this, left, top, width, height, false, borderColor, borderWidth);
      }

    }
  }

  function _renderRect(x, y, w, h, isFill=true, color, lineWidth){ // 画直角矩形
    lineWidth && (this.lineWidth = lineWidth);
    color && (isFill ? this.fillStyle = color: this.strokeStyle= color);
    isFill? this.fillRect(x, y, w, h): this.strokeRect(x, y, w, h);
  }


  function _renderRoundRect( x, y, w, h, r, isFill=true, color, lineWidth) { // 画圆角矩形
    // 开始绘制
    lineWidth && (this.lineWidth = lineWidth);
    r = parseInt(r);
    this.beginPath();
    // 因为边缘描边存在锯齿，最好指定使用 transparent 填充
    // 这里是使用 fill 还是 stroke都可以，二选一即可
    color && (isFill ? this.fillStyle = color: this.strokeStyle= color);
    // 左上角
    this.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);

    // border-top
    this.moveTo(x + r, y);
    this.lineTo(x + w - r, y);
    //this.lineTo(x + w, y + r);
    // 右上角
    this.arc(x + w - r, y + r, r, Math.PI * 1.5, Math.PI * 2);

    // border-right
    this.lineTo(x + w, y + h - r);
    //this.lineTo(x + w - r, y + h);
    // 右下角
    this.arc(x + w - r, y + h - r, r, 0, Math.PI * 0.5);

    // border-bottom
    this.lineTo(x + r, y + h);
    //this.lineTo(x, y + h - r);
    // 左下角
    this.arc(x + r, y + h - r, r, Math.PI * 0.5, Math.PI);

    // border-left
    this.lineTo(x, y + r);
    //this.lineTo(x + r, y);

    // 这里是使用 fill 还是 stroke都可以，二选一即可，但是需要与上面对应
    isFill? this.fill(): this.stroke();
    this.closePath();
    // 剪切
    //this.clip();
  }

  function _renderCircle ( x, y, r, isFill = true, color, lineWidth) { // 画圆
    lineWidth && (this.lineWidth = lineWidth);
    color && (isFill ? this.fillStyle = color: this.strokeStyle= color);
    this.arc(x, y, r, 0, 2 * Math.PI);
    isFill? this.fill() : this.stroke();
  }

  function _renderImage (src, x, y, w, h) { // 画图片
    this.drawImage(src, x, y, w, h);
  }

  function _renderText (text, x, y) { // 画文字
    this.fillText(text, x, y);
  }

  function _clearRect (x, y, w, h) {
    this.clearRect(x, y, w, h);
  }

  function _getDownFileUrl (url) { // 获取下载后的图片临时路径
    // checkout

    !/https/.test(url) && (url = url.replace('http', 'https'));
    // parse url
    return new Promise((resolve, reject) => {
      mpvue.downloadFile({
        url: url,
        success: function(res) {
          if (res.statusCode === 200) {
            resolve(res.tempFilePath);
          } else {
            resolve("");
            console.log("出错");
          }
        },
        fail: function() {
          resolve("");
          console.log("服务器无返回");
        }
      });
    });
  }

  function _getCanvasTempFilePath (canvasId) { // 获取canvas输出的临时路径
    return new Promise(resolve => {
      setTimeout(() => {

        mpvue.canvasToTempFilePath({
          canvasId,
          success(res) {
            resolve(res.tempFilePath);
          },

          fail() {
            resolve("");
          }
        });

      }, 600);

    });
  }

  // output
  return { render: render };
});

/*
  Communication between components

  events = {
    eventType1: [{self, handler}, {self, handler}, {self, handler}, ...],
    eventType2: ['event1', 'event2', {self, handler}, ...],
    eventType3: ['event1', 'event2', {self, handler}, ...],
    eventType4: ['event1', 'event2', {self, handler}, ...]
  }
  
*/
myModule.define('event', ['types'], function(types){ 
  // Register Event Listener
  var events = {};
  function on (type, self, handler) {

    var curQueues = events[type];
    var event = {
      self: self,
      handler: handler
    };
    if (curQueues && types.isArray(curQueues)) { // There are queues of this type
      for (var i= 0; i< curQueues.length; i++) { // prevent repeat listener
        if(curQueues[handler] === self && JSON.stringify(handler) === JSON.stringify(curQueues[handler])) return
      }
      curQueues.push(event);
    }else { // No queues of this type
      events[type] = [event];
    }
  }
  // emit event
  function emit (type, data) {
    var curQueues, event;
    curQueues = events[type];

    if(curQueues && curQueues.length) {
      while (curQueues.length) {
        event = curQueues.shift();
        event.handler.call(event.self, data);
      }
    }

  }

  // remove event listener
  function remove (type, self, handler) {
    var curQueues, event, i;
    curQueues = events[type];

    if(curQueues && curQueues.length) {
      i = curQueues.length;
      while (i--) {
        event = curQueues[i];
        if (event.self === self && JSON.stringify(event.handler) === JSON.stringify(handler)) {
          curQueues.splice(i, 1);
        }
      }
    }

  }

  return {on: on, emit: emit, remove: remove};
});

myModule.define('myArray', [], function(){
  function sum (arr) {
    var i = arr.length,
        count = 0;
    while (i--) {
      count += +arr[i];
    }
    return count;
  }

  return {sum: sum};

});


export default myModule;
